#ifndef _SYS_USW_DIAG_H
#define _SYS_USW_DIAG_H
#ifdef __cplusplus
extern "C" {
#endif

#include "sal.h"
#include "ctc_diag.h"
#include "sys_usw_common.h"
#include "sys_usw_packet.h"

#define SYS_DIAG_DROP_REASON_BASE_IPE 0
#define SYS_DIAG_DROP_REASON_BASE_EPE 64
#define SYS_DIAG_LIST_MAX_NUM   9600

#define SYS_DIAG_DROP_COUNT_SYSTEM 0xFFFF

#define SYS_DIAG_DBG_OUT(level, FMT, ...) \
    CTC_DEBUG_OUT(diag, diag, DIAG_SYS, level, FMT, ## __VA_ARGS__)
    
#define ARRAY(a, i)  ((i) < (sizeof(a)/sizeof(a[0])))?(a[i]):0
#define STR_ARRAY(a, i)  ((i) < (sizeof(a)/sizeof(a[0])))?(a[i]):""

#define SYS_DIAG_TCAM_NUM 19
#define SYS_DIAG_TCAM_BMP_IN_WORD 64
#define SYS_DIAG_BASIC_STACKING_HEADER_LEN 32
#define SYS_DIAG_HDR_DATA_LENGTH_WORD    12
typedef uint32 sys_diag_tcam_bmp[SYS_DIAG_TCAM_BMP_IN_WORD];

#define DIAG_INFO_PKT_HDR(POS, STR, HDR,LEN)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_PKT_HDR;\
        sal_memcpy(p_rslt->info[p_rslt->real_count].val.pkt_hdr, HDR, LEN * sizeof(uint8));\
        p_rslt->info[p_rslt->real_count].u32_cnt = LEN;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;
    
typedef struct sys_usw_diag_s
{
    ctc_slist_t* drop_pkt_list;  /* refer to sys_usw_diag_drop_pkt_node_t */
    ctc_hash_t*  drop_hash;      /* node refer to sys_usw_diag_drop_info_t*/
    sal_mutex_t* diag_mutex;

    ctc_diag_drop_pkt_report_cb drop_pkt_report_cb;
    uint32 drop_pkt_store_cnt;   /* determine the pkt_list count */
    uint32 drop_pkt_store_len;
    uint16 drop_pkt_hash_len;
    uint8  drop_pkt_overwrite;/* when set, if store drop packet count exceed drop_pkt_store_cnt, overwite the oldest buffer */
    uint8  rsv;
    ctc_hash_t* lb_dist;
    uint32 drop_pkt_id;  /* 0 means invalid, <1-0xFFFFFFFF>*/
	uint32 cur_discard_type_map ;   /* (pos << 16) | discard_type */
    uint32 cur_exception_map ;  /* (excp_index << 16) | excp_sub_index */
}sys_usw_diag_t;

#define DIAG_EDITTYPE_INVALID                         0x0
#define DIAG_EDITTYPE_TYPE1X                          0x4
#define DIAG_EDITTYPE_TYPE2X                          0x5
#define DIAG_EDITTYPE_TYPE4X                          0x6
#define DIAG_EDITTYPE_TYPE8X                          0x7

#define DIAG_L2EDIT_TYPE_NONE                          0x0
#define DIAG_L2EDIT_TYPE_ADDETH1X                      0x1
#define DIAG_L2EDIT_TYPE_ADDETH2X                      0x2
#define DIAG_L2EDIT_TYPE_ADDRAW                        0x3
#define DIAG_L2EDIT_TYPE_AUTOETH1X                     0x4
#define DIAG_L2EDIT_TYPE_AUTOETH2X                     0x5
#define DIAG_L2EDIT_TYPE_RWETH1X                       0x9
#define DIAG_L2EDIT_TYPE_RWETH2X                       0xa
#define DIAG_L2EDIT_TYPE_GEMPORT                       0xe
#define DIAG_L2EDIT_TYPE_LOOPBACK                      0xf

#define DIAG_L3EDITTYPE_NONE            0x0
#define DIAG_L3EDITTYPE_ADDIP4          0x1
#define DIAG_L3EDITTYPE_ADDIP44X        0x2
#define DIAG_L3EDITTYPE_ADDIP6          0x3
#define DIAG_L3EDITTYPE_MPLS1X          0x4
#define DIAG_L3EDITTYPE_MPLS2X          0x5
#define DIAG_L3EDITTYPE_MPLS4X          0x6
#define DIAG_L3EDITTYPE_ADDRAW          0x7
#define DIAG_L3EDITTYPE_RWIP41X         0x8
#define DIAG_L3EDITTYPE_RWIP4           0x9
#define DIAG_L3EDITTYPE_RWIP6           0xa
#define DIAG_L3EDITTYPE_RWFLEX          0xb
#define DIAG_L3EDITTYPE_INSFLEX         0xc
#define DIAG_L3EDITTYPE_DELMPLS         0xd
#define DIAG_L3EDITTYPE_DELFLEX         0xe
#define DIAG_L3EDITTYPE_LOOPBACK        0xf
#define DIAG_L3EDITTYPE_ADDTRILL        0x10
#define DIAG_L3EDITTYPE_RWIP68X         0x11
#define DIAG_L3EDITTYPE_ADDIP68X        0x12
#define DIAG_L3EDITTYPE_RWIP62X         0x13

#define DIAG_PLD_OP_NONE                    0x0
#define DIAG_PLD_OP_ROUTE                   0x1
#define DIAG_PLD_OP_BRIDGE                  0x2
#define DIAG_PLD_OP_BRIDGE_VPLS             0x3
#define DIAG_PLD_OP_BRIDGE_INNER            0x4
#define DIAG_PLD_OP_MIRROR                  0x5
#define DIAG_PLD_OP_ROUTE_NOTTL             0x6
#define DIAG_PLD_OP_ROUTE_COMPACT           0x7

#define DIAG_ACL_METADATA_TYPE_INVALID                  0
#define DIAG_ACL_METADATA_TYPE_METADATA                 1
#define DIAG_ACL_METADATA_TYPE_FID                      2
#define DIAG_ACL_METADATA_TYPE_VRFID                    3

#define DIAG_INT_ENCAP_TYPE_NONE                        0
#define DIAG_INT_ENCAP_TYPE_TCPRAW                      1
#define DIAG_INT_ENCAP_TYPE_TCPPROBE                    2
#define DIAG_INT_ENCAP_TYPE_UDPRAW                      3
#define DIAG_INT_ENCAP_TYPE_UDPPROBE                    4

#define DIAG_L3TYPE_NONE                              0x0
#define DIAG_L3TYPE_IP                                0x1
#define DIAG_L3TYPE_IPV4                              0x2
#define DIAG_L3TYPE_IPV6                              0x3
#define DIAG_L3TYPE_MPLS                              0x4
#define DIAG_L3TYPE_MPLSUP                            0x5
#define DIAG_L3TYPE_ARP                               0x6
#define DIAG_L3TYPE_FCOE                              0x7
#define DIAG_L3TYPE_TRILL                             0x8
#define DIAG_L3TYPE_ETHEROAM                          0x9
#define DIAG_L3TYPE_SLOWPROTO                         0xa
#define DIAG_L3TYPE_RESERVED                          0xb
#define DIAG_L3TYPE_PTP                               0xc
#define DIAG_L3TYPE_DOT1AE                            0xd
#define DIAG_L3TYPE_SATPDU                            0xe
#define DIAG_L3TYPE_FLEXIBLE                          0xf

#define DIAG_L4TYPE_NONE                              0x0
#define DIAG_L4TYPE_TCP                               0x1
#define DIAG_L4TYPE_GRE                               0x2
#define DIAG_L4TYPE_UDP                               0x3
#define DIAG_L4TYPE_IPINIP                            0x4
#define DIAG_L4TYPE_V6INIP                            0x5
#define DIAG_L4TYPE_ICMP                              0x6
#define DIAG_L4TYPE_IGMP                              0x7
#define DIAG_L4TYPE_IPINV6                            0x8
#define DIAG_L4TYPE_RESERVED                          0x9
#define DIAG_L4TYPE_ACHOAM                            0xa
#define DIAG_L4TYPE_V6INV6                            0xb
#define DIAG_L4TYPE_RDP                               0xc
#define DIAG_L4TYPE_SCTP                              0xd
#define DIAG_L4TYPE_DCCP                              0xe
#define DIAG_L4TYPE_FLEXIBLE                          0xf

#define DIAG_INFO_NONE(POS, STR)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_NONE;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_CHAR(POS, STR, STR_OUT)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_CHAR;\
        sal_strncpy(p_rslt->info[p_rslt->real_count].val.str, (STR_OUT), (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_UINT32(POS, STR, U32)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_UINT32;\
        p_rslt->info[p_rslt->real_count].val.u32 = U32;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_U32_HEX(POS, STR, U32)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_U32_HEX;\
        p_rslt->info[p_rslt->real_count].val.u32 = U32;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_U32_LIST(POS, STR, PU32, LEN)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        uint8  _loop_ = 0;\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_U32_LIST;\
        for (_loop_=0; _loop_<LEN; _loop_++)    {\
            p_rslt->info[p_rslt->real_count].val.u32_list[_loop_] = PU32[_loop_];\
        }\
        p_rslt->info[p_rslt->real_count].u32_cnt = LEN;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_UINT64(POS, STR, U64)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_UINT64;\
        p_rslt->info[p_rslt->real_count].val.u64 = U64;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_U64_HEX(POS, STR, U64)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_U64_HEX;\
        p_rslt->info[p_rslt->real_count].val.u64 = U64;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_MAC(POS, STR, HW_MAC)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_MAC;\
        SYS_USW_SET_USER_MAC(p_rslt->info[p_rslt->real_count].val.mac,HW_MAC);\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_IP4(POS, STR, V4)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_IPv4;\
        p_rslt->info[p_rslt->real_count].val.ipv4 = V4;\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_IP6(POS, STR, V6)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_IPv6;\
        p_rslt->info[p_rslt->real_count].val.ipv6[0] = V6[3];\
        p_rslt->info[p_rslt->real_count].val.ipv6[1] = V6[2];\
        p_rslt->info[p_rslt->real_count].val.ipv6[2] = V6[1];\
        p_rslt->info[p_rslt->real_count].val.ipv6[3] = V6[0];\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_INFO_UDF(POS, STR, UDF)\
    if (p_rslt->real_count < p_rslt->count)\
    {\
        sal_strncpy(p_rslt->info[p_rslt->real_count].str, STR, (CTC_DIAG_TRACE_STR_LEN - 1));\
        p_rslt->info[p_rslt->real_count].val_type = CTC_DIAG_VAL_UDF;\
        p_rslt->info[p_rslt->real_count].val.udf[0] = UDF[3];\
        p_rslt->info[p_rslt->real_count].val.udf[1] = UDF[2];\
        p_rslt->info[p_rslt->real_count].val.udf[2] = UDF[1];\
        p_rslt->info[p_rslt->real_count].val.udf[3] = UDF[0];\
        p_rslt->info[p_rslt->real_count].position = POS;\
    }\
    p_rslt->real_count++;

#define DIAG_SET_USR_UDF(granularity,DST,SRC)\
        if(granularity) \
        { \
            (DST)[3]=(((SRC)[0]&0x000000FF)<<8|((SRC)[0]&0x0000FF00)>>8|((SRC)[0]&0xFF000000)>>8|((SRC)[0]&0x00FF0000)<<8);\
            (DST)[2]=(((SRC)[1]&0x000000FF)<<8|((SRC)[1]&0x0000FF00)>>8|((SRC)[1]&0xFF000000)>>8|((SRC)[1]&0x00FF0000)<<8);\
            (DST)[1]=(((SRC)[2]&0x000000FF)<<8|((SRC)[2]&0x0000FF00)>>8|((SRC)[2]&0xFF000000)>>8|((SRC)[2]&0x00FF0000)<<8);\
            (DST)[0]=(((SRC)[3]&0x000000FF)<<8|((SRC)[3]&0x0000FF00)>>8|((SRC)[3]&0xFF000000)>>8|((SRC)[3]&0x00FF0000)<<8);\
        } \
        else \
    {\
        (DST)[3]=(((SRC)[0]&0x000000FF)<<24|((SRC)[0]&0x0000FF00)<<8|((SRC)[0]&0xFF000000)>>24|((SRC)[0]&0x00FF0000)>>8);\
        (DST)[2]=(((SRC)[1]&0x000000FF)<<24|((SRC)[1]&0x0000FF00)<<8|((SRC)[1]&0xFF000000)>>24|((SRC)[1]&0x00FF0000)>>8);\
        (DST)[1]=(((SRC)[2]&0x000000FF)<<24|((SRC)[2]&0x0000FF00)<<8|((SRC)[2]&0xFF000000)>>24|((SRC)[2]&0x00FF0000)>>8);\
        (DST)[0]=(((SRC)[3]&0x000000FF)<<24|((SRC)[3]&0x0000FF00)<<8|((SRC)[3]&0xFF000000)>>24|((SRC)[3]&0x00FF0000)>>8);\
    }


#define DIAG_PP_EN(cmd,type_pp_bmp,type)  (CTC_IS_BIT_SET(type_pp_bmp, type) ? DRV_CMD_PP_EN(cmd) : cmd)


extern sys_usw_diag_t* p_usw_diag_master[CTC_MAX_LOCAL_CHIP_NUM_PP];

extern int32
sys_usw_diag_mem_bist(uint8 lchip, ctc_diag_bist_mem_type_t mem_type, uint8* err_mem_id);

extern int32
sys_usw_diag_pkt_trace_key_check_and_clear_rslt(uint8 lchip, ctc_diag_pkt_trace_t* p_trace);

extern int32
sys_usw_diag_trigger_pkt_trace(uint8 lchip, ctc_diag_pkt_trace_t* p_trace);

extern int32
sys_usw_diag_get_pkt_trace(uint8 lchip, ctc_diag_pkt_trace_result_t* p_rslt, uint8 position);

extern int32
sys_usw_diag_get_drop_info(uint8 lchip, ctc_diag_drop_t* p_drop);

extern int32
sys_usw_diag_init(uint8 lchip, void* init_cfg);

extern int32
sys_usw_diag_deinit(uint8 lchip);

extern int32
sys_usw_diag_set_property(uint8 lchip, ctc_diag_property_t prop, void* p_value);

extern int32
sys_usw_diag_get_property(uint8 lchip, ctc_diag_property_t prop, void* p_value);

extern int32
sys_usw_diag_tbl_control(uint8 lchip, ctc_diag_tbl_t* p_para);

extern int32
sys_usw_diag_set_lb_distribution(uint8 lchip, ctc_diag_lb_dist_t* p_para);

extern int32
sys_usw_diag_get_lb_distribution(uint8 lchip, ctc_diag_lb_dist_t* p_para);

extern int32
sys_usw_diag_get_mem_usage(uint8 lchip, ctc_diag_mem_usage_t* p_para);

extern int32
sys_usw_diag_get_queue_depth(uint8 lchip, ctc_diag_queue_depth_t* p_queue_query);
extern int32
sys_usw_diag_tcam_mbist_api(uint8 lchip, uint8* err_mem_id, uint8* err_cnt);
extern int32
sys_usw_diag_tcam_function_bist_api(uint8 lchip, uint8 error_mem_id,uint16* err_entry_cnt,sys_diag_tcam_bmp* p_bmp);

extern int32
sys_usw_diag_get_lb_hash(uint8 lchip, ctc_field_key_t* p_field_list, uint32 field_cnt, ctc_diag_lb_hash_t* p_rslt);
#ifdef __cplusplus
}
#endif

#endif  /*_SYS_USW_DIAG_H*/